package timbap.visualizer.coreplugins;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import timbap.visualizer.api.model.TimeCode;
import timbap.visualizer.api.plugin.container.AbstractKeepAliveModeController;


public abstract class AbstractBrowsingController extends AbstractKeepAliveModeController {
    
    private static final Log LOG = LogFactory.getLog(AbstractBrowsingController.class);
    
    private int nextRecordItemIndex;
    private float rotation;

	protected abstract void updateRecordItems();

    @Override
    public void timeCodeUpdated(TimeCode pTimeCode) {
        
        super.timeCodeUpdated(pTimeCode);
        float tAbsolutePositionDelta = getTimeCode().getAbsolutePositionDelta();
        
        calcTurntableRotation();
        
        int tRecordItemCount = getContext().getRecordItemManager().getRecordItemCount();
        
        int tOldSelectedRecordItemIndex = getContext().getRecordItemManager().getSelectedRecordItemIndex();
        int tOldNextRecordItemIndex = nextRecordItemIndex;
        
        int tNewNextRecordItemIndex = (int)(rotation * tRecordItemCount);
        int tNewSelectedRecordItemIndex = (tNewNextRecordItemIndex + (int)(Math.floor(tRecordItemCount) / 2)) % tRecordItemCount;
        if (tAbsolutePositionDelta > 0) {
            tNewNextRecordItemIndex = (tNewNextRecordItemIndex + tRecordItemCount - 1) % tRecordItemCount;
        }
        
        updateRecordItems();
        
        if (tNewSelectedRecordItemIndex != tOldSelectedRecordItemIndex) {
            handleSelectionChange(tOldSelectedRecordItemIndex, tNewSelectedRecordItemIndex);
        }
        
        if (tNewNextRecordItemIndex != tOldNextRecordItemIndex) {
            int tNextPlaylistIndex = (int)(getTimeCode().getNormalizedAbsolutePosition()
                    * getContext().getPlaylistManager().getPlaylistSize());
            if (tAbsolutePositionDelta > 0) {
                tNextPlaylistIndex = (tNextPlaylistIndex + tRecordItemCount - 1) % getContext().getPlaylistManager().getPlaylistSize();
            }
            if (!getTimeCode().hasJumped()) {
            	loadNextPlaylistEntry(tOldNextRecordItemIndex, tNewNextRecordItemIndex, tNextPlaylistIndex);
            } else {
            	LOG.info("Timecode has jumped.");
            	int[] tRecordIndices = recalcPlaylistIndices(tNextPlaylistIndex, tNewNextRecordItemIndex, getTimeCode().isReverse());
            	LOG.info("Indices calculated.");
            	resetPlaylistEntries(tNewNextRecordItemIndex, tOldNextRecordItemIndex, tRecordIndices);
            }
        }

    }


    private int[] recalcPlaylistIndices(int pStartPlaylistIndex, int pStartRecordItemIndex, boolean pIsReverse) {
    	
    	int tPlaylistSize = getContext().getPlaylistManager().getPlaylistSize();
    	int tRecordItemCount = getContext().getRecordItemManager().getRecordItemCount();
    	int tStep = (pIsReverse) ? 1 : -1;
    	
    	int[] tPlaylistIndices = new int[getContext().getRecordItemManager().getRecordItemCount()];
    	for (int i=0; Math.abs(i) < tPlaylistIndices.length; i = i + tStep) {
			int tRecordItemIndexToSet = ((pStartRecordItemIndex - i) + tRecordItemCount) % tRecordItemCount;
			int tPlaylistIndexToSet = ((pStartPlaylistIndex - i) + tPlaylistSize) % tPlaylistSize;
    		tPlaylistIndices[tRecordItemIndexToSet] = tPlaylistIndexToSet;
    	}
		
		return tPlaylistIndices;
	}

	protected void calcTurntableRotation() {
        
        float tRotation = 0;
        if (getContext().getRecordItemManager().getRecordItemCount() > 0) {
            float tRecordItemRotation = getTimeCode().getNormalizedAbsolutePosition()
                                  * getContext().getPlaylistManager().getPlaylistSize()
                                  / getContext().getRecordItemManager().getRecordItemCount();
            tRotation = (tRecordItemRotation - (int)Math.floor(tRecordItemRotation));
        }
        rotation = tRotation;
    }



    protected void handleSelectionChange(int pOldSelectedItemIndex,
                                         int pNewSelectedItemIndex) {
        
        keepAlive();
        getContext().getRecordItemManager().setSelectedRecordItemIndex(pNewSelectedItemIndex);
        if (LOG.isDebugEnabled()) {
            LOG.debug("selected item index changed from " 
                    + pOldSelectedItemIndex + " to " + pNewSelectedItemIndex);
        }
    }
    
    protected void loadNextPlaylistEntry(int pOldNextRecordItemIndex,
                                         int pNewNextRecordItemIndex,
                                         int pNextPlaylistIndex) {
        
        nextRecordItemIndex = pNewNextRecordItemIndex;
        if (LOG.isDebugEnabled()) {
            LOG.debug("next record item index changed from "
                    + pOldNextRecordItemIndex + " to " + nextRecordItemIndex);
            LOG.debug("playlist entry to load for the next record item is " + pNextPlaylistIndex);
        }

    }


    public float getRotation() {
        return rotation;
    }
    
    
	protected void resetPlaylistEntries(int pNewNextRecordItemIndex, int pOldNextRecordItemIndex, int[] pPlaylistIndices) {
		nextRecordItemIndex = pNewNextRecordItemIndex;
        if (LOG.isDebugEnabled()) {
            LOG.debug("next record item index changed from " 
                    + pOldNextRecordItemIndex + " to " + nextRecordItemIndex);
            LOG.debug("playlist entry to load for the next record item is " + pPlaylistIndices[pNewNextRecordItemIndex]);
        }
	}


}
